//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<lock.h>
///	@path	~/src/lib/system/
///	@date	2007/06/23
///	@desc	Lock implementation.

#pragma once

#include "xeres.h"

#include "lib/utilities/time.h"

namespace xeres {

	/*!
		\class	ThreadLock
		\brief	Most common threading lock.

		\sa SpinLock, GlobalLock
	*/
	class ThreadLock
	{
	public:
		
		/// \name Constructor & Destructor
		//@{

		/// \ctor
		ThreadLock( void );

		/// \dtor
		~ThreadLock( void );

		//@}

		/// \name Lock Manipulation
		//@{

		/*!
			\brief		Get current lock, wait until acquired if it's locked.
		*/
		void Acquire( void );

		/*!
			\brief		Release current lock.
		*/
		void Release( void );

		/*!
			\brief		Try to get lock in wait time, return lock result.
						If got lock, it must be released.
		*/
		bool TryAcquire( const Time& wait );

		/*!
			\brief		Try to get lock, return lock result immediately.
						If got lock, it must be released.
		*/
		bool TryAcquire( void );

		//@}

	private:

		// internal implementation structure
		void *		m_lockImpl;
	};

	/*!
		\class	SpinLock
		\brief	Xeres's own spin lock implementation.

		\sa ThreadLock, GlobalLock
	*/
	class SpinLock
	{
	public:

		/// \name Constructor & Destructor
		//@{

		/// \ctor
		SpinLock( void );

		/// \dtor
		~SpinLock( void );

		//@}

		/// \name Lock Manipulation
		//@{

		/*!
			\brief		Get current lock, wait until acquired if it's locked.
		*/
		void Acquire( void );

		/*!
			\brief		Release current lock.
		*/
		void Release( void );

		/*!
			\brief		Try to get lock in wait time, return lock result.
						If got lock, it must be released.
		*/
		bool TryAcquire( const Time& wait );

		/*!
			\brief		Try to get lock, return lock result immediately.
						If got lock, it must be released.
		*/
		bool TryAcquire( void );

		//@}

	private:

		// spin lock
		void *		m_monitor;

	};

	/*!
		\class	GlobalLock
		\brief	IPC named lock.

		\sa ThreadLock, SpinLock
	*/
	class GlobalLock
	{
	public:

		/// \name Constructor & Destructor
		//@{

		/// \ctor
		GlobalLock( const WString& name , bool open_exist );

		/// \ctor_set
		GlobalLock( const GlobalLock& rhs );

		/// \dtor
		~GlobalLock( void );

		//@}

		/// \name Lock Manipulation
		//@{

		/*!
			\brief		Get current lock, wait until acquired if it's locked.
		*/
		void Acquire( void );

		/*!
			\brief		Release current lock.
		*/
		void Release( void );

		/*!
			\brief		Try to get lock in wait time, return lock result.
						If got lock, it must be released.
		*/
		bool TryAcquire( const Time& wait );

		/*!
			\brief		Try to get lock, return lock result immediately.
						If got lock, it must be released.
		*/
		bool TryAcquire( void );

		//@}

	private:

		// internal implementation structure
		void *		m_lockImpl;
	};

	/*!
		\class	LockGuard
		\brief	scope guard of lock.

		\sa LockGuardWrap
	*/
	template< typename _LockType > class LockGuard
	{
	public:

		/// \ctor
		LockGuard( _LockType& lock )
			: m_lock( lock )
		{
			m_lock.Acquire();
		}

		/// \dtor
		~LockGuard( void )
		{
			m_lock.Release();
		}

	private:

		_LockType&	m_lock;
	};

	/*!
		\class	LockGuardWrap
		\brief	lock guard wrap.

		\sa LockGuard
	*/
	template< typename _LockType > class LockGuardWrap
	{
	public:

		/// \name Constructor & Destructor
		//@{

		/// \ctor
		LockGuardWrap( _LockType& lock , bool lock_now = true )
			: m_lock( lock )
			, m_locked( false )
		{
			if( lock_now )
				this->Acquire();
		}

		/// \dtor
		~LockGuardWrap( void )
		{
			if( m_locked )
				Release();
		}

		//@}

		/// \name Lock Manipulation
		//@{

		/*!
			\brief		Get current lock, wait until acquired if it's locked.
		*/
		void Acquire( void )
		{
			assert( !m_locked );
			m_lock.Acquire();
			m_locked = true;
		}

		/*!
			\brief		Release current lock.
		*/
		void Release( void )
		{
			assert( m_locked );
			m_lock.Release();
			m_locked = false;
		}

		/*!
			\brief		Try to get lock in wait time, return lock result.
						If got lock, it must be released.
		*/
		bool TryAcquire( const Time& wait )
		{
			assert( !m_locked );
			return m_locked = m_lock.TryAcquire( wait );
		}

		/*!
			\brief		Try to get lock in wait time, return lock result.
						If succeed, the lock must be released later.
		*/
		bool TryAcquire( void )
		{
			assert( !m_locked );
			return m_locked = m_lock.TryAcquire();
		}

		//@}

	private:

		_LockType&	m_lock;

		bool		m_locked;
	};
	
} // namespace xeres

#include "lib/system/lock.inl"
